namespace BizTalk.Mapper.CustomComponents.Converters
{
    using System;
    using Microsoft.BizTalk.BaseFunctoids;
    using System.Reflection;
    using System.Text;
    using System.Collections;
    using System.Globalization;


	/// <summary>
	/// The following Custom functoid does a Packed Decimal Conversion. It takes three inputs and
	/// return the Signed Packed Decimal string value.
	/// </summary>
	public class ConvertToPackedDecimal : BaseFunctoid
	{
        public ConvertToPackedDecimal() : base()
		{
			//ID for this functoid
			this.ID = 4001;

			// resource assembly
            SetupResourceAssembly("BizTalk.Mapper.CustomComponents.Converters.PackedDecimalConverterResources", Assembly.GetExecutingAssembly());

			//Setup the Name, ToolTip, Help Description, and the Bitmap for this functoid
			SetName("IDS_TOPACKEDDECIMALCONVERTER_NAME");
            SetTooltip("IDS_TOPACKEDDECIMALCONVERTER_TOOLTIP");
            SetDescription("IDS_TOPACKEDDECIMALCONVERTER_DESCRIPTION");
            SetBitmap("IDB_TOPACKEDDECIMALCONVERTER_BITMAP");

			this.SetMinParams(3);
			this.SetMaxParams(3);

            SetExternalFunctionName(GetType().Assembly.FullName, "BizTalk.Mapper.CustomComponents.Converters.ConvertToPackedDecimal", "ToPackedDecimal");


			//Add this functoid to Map Lib.
			this.Category = FunctoidCategory.Conversion;
			this.OutputConnectionType = ConnectionType.All;

			AddInputConnectionType(ConnectionType.AllExceptRecord); //first input
			AddInputConnectionType(ConnectionType.AllExceptRecord); //second input
            AddInputConnectionType(ConnectionType.AllExceptRecord); //third input
		}

		//this is the function that gets called when the Map is executed which has this functoid.
        public string ToPackedDecimal(string val1, string val2, string val3)
		{
            // Variables 
            double  numberToConver      = 0;
            int     precesionLength     = 0;
            int     floatDigitCount     = 0;

            // Validations
            try
            {
                numberToConver = double.Parse(val1);
                precesionLength = int.Parse(val2);
                floatDigitCount = int.Parse(val3);
            }
            catch (Exception exp)
            {
                throw new Exception("Input is not valid, " + exp.Message, exp);
            }


            // Initiation
            bool isNegative = false;
            string codeCharsPositive = "{ABCDEFGHI";
            string codeCharsNegative = "}JKLMNOPQR";

            // Check if the number is negative
            if (numberToConver < 0)
            {
                isNegative = true;
                numberToConver = -numberToConver;
            }

            // Float digits
            if (floatDigitCount > 0)
            {
                numberToConver = numberToConver * (Math.Pow(10, floatDigitCount));
            }

            // Prepare packed number
            string packedNumber = numberToConver.ToString();

            if (packedNumber.IndexOf(".") > -1)
            {
                // Truncate remaining float digits
                packedNumber = packedNumber.Substring(0, packedNumber.IndexOf("."));
            }

            // Fill padding zeros
            if (packedNumber.Length < precesionLength)
            {
                packedNumber = packedNumber.PadLeft(precesionLength, '0');
            }

            // Specify sign of the number
            int lastDigit = Convert.ToInt32(packedNumber.Substring(packedNumber.Length - 1, 1));

            if (isNegative)
            {
                // Negative
                packedNumber = packedNumber.Substring(0, packedNumber.Length - 1);
                packedNumber += codeCharsNegative.Substring(lastDigit, 1).ToString();
            }
            else
            {
                // Positive
                packedNumber = packedNumber.Substring(0, packedNumber.Length - 1);
                packedNumber += codeCharsPositive.Substring(lastDigit, 1).ToString();
            }

            // Return
            return packedNumber;			
		}
	}


    /// <summary>
    /// The following Custom functoid does a Packed Decimal Conversion. It takes two inputs and
    /// return the double value represent the Packed Decimal value.
    /// </summary>
    public class ConvertPackedDecimalToString : BaseFunctoid
    {
        public ConvertPackedDecimalToString() : base()
        {
            //ID for this functoid
            this.ID = 4002;

            // resource assembly
            SetupResourceAssembly("BizTalk.Mapper.CustomComponents.Converters.PackedDecimalConverterResources", Assembly.GetExecutingAssembly());

            //Setup the Name, ToolTip, Help Description, and the Bitmap for this functoid
            SetName("IDS_FROMPACKEDDECIMALCONVERTER_NAME");
            SetTooltip("IDS_FROMPACKEDDECIMALCONVERTER_TOOLTIP");
            SetDescription("IDS_FROMPACKEDDECIMALCONVERTER_DESCRIPTION");
            SetBitmap("IDB_FROMPACKEDDECIMALCONVERTER_BITMAP");

            this.SetMinParams(2);
            this.SetMaxParams(2);

            SetExternalFunctionName(GetType().Assembly.FullName, "BizTalk.Mapper.CustomComponents.Converters.ConvertPackedDecimalToString", "FromPackedDecimal");


            //Add this functoid to Map Lib.
            this.Category = FunctoidCategory.Conversion;
            this.OutputConnectionType = ConnectionType.All;

            AddInputConnectionType(ConnectionType.AllExceptRecord); //first input
            AddInputConnectionType(ConnectionType.AllExceptRecord); //second input            
        }

        //this is the function that gets called when the Map is executed which has this functoid.
        public string FromPackedDecimal(string val1, string val2)
        {
            // Variables 
            string packedDecimal = "0";
            int floatDigitCount = 0;

            // Validations
            try
            {
                // TODO: some validation to be added
                packedDecimal = val1;
                floatDigitCount = int.Parse(val2);
            }
            catch (Exception exp)
            {
                throw new Exception("Input is not valid, " + exp.Message, exp);
            }

            // Number Converter
            string codeChar = null;
            double resultedNumber = 0;
            string codeCharsPositive = "{ABCDEFGHI";
            string codeCharsNegative = "}JKLMNOPQR";

            // Validate input string
            packedDecimal = packedDecimal.Trim();
            if (packedDecimal == string.Empty)
            {
                return "0";
            }

            codeChar = packedDecimal.Substring(packedDecimal.Length - 1);

            // Negative Number
            if (codeCharsPositive.IndexOf(codeChar) > -1)
            {
                packedDecimal = packedDecimal.Substring(0, packedDecimal.Length - 1) + codeCharsPositive.IndexOf(codeChar);
                resultedNumber = Convert.ToDouble(packedDecimal);
            }

            // Positive Number
            else if (codeCharsNegative.IndexOf(codeChar) > -1)
            {
                packedDecimal = packedDecimal.Substring(0, packedDecimal.Length - 1) + codeCharsNegative.IndexOf(codeChar);
                resultedNumber = -Convert.ToDouble(packedDecimal);
            }

            else
            {
                // no signed number
                resultedNumber = double.Parse(packedDecimal);
            }

            if (floatDigitCount > 0)
            {
                return (resultedNumber / (Math.Pow(10, floatDigitCount))).ToString();
            }
            else
            {
                return resultedNumber.ToString();
            }
        }
    }
}
